package org.dftproject.genesis.ui.figures.dualtree;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dftproject.genesis.ui.pages.pedigree.tree.CoupleFigure;
import org.dftproject.genesis.ui.pages.pedigree.tree.OneToManyConnection;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.IFigure;

public class DualTreeFigure extends Figure {
	
	private IFigure root;
	private final Map<IFigure, List<IFigure>> ancestorsByNode = new HashMap<IFigure, List<IFigure>>();
	private final Map<IFigure, List<IFigure>> descendantsByNode = new HashMap<IFigure, List<IFigure>>();
	
	private final Map<IFigure, OneToManyConnection> ancestorConnections = new HashMap<IFigure, OneToManyConnection>();
	
	private ISelectableFigure selectedNode;

	public DualTreeFigure() {
	}
	
	public void setRoot(IFigure node) {
		if (root != null)
			throw new IllegalStateException("root is already set");
		root = node;
		
		decorateNode(root);
		add(root);
		
		OneToManyConnection connection = createOneToManyConnection();
		connection.setSourceAnchor(root);
		ancestorConnections.put(root, connection);
		add(connection);
	}

	public void addAncestor(IFigure node, IFigure ancestor) {
		addAncestor(node, ancestor, -1);
	}

	public void addAncestor(IFigure node, IFigure ancestor, int position) {
		// Add ancestor as an ancestor of node
		
		List<IFigure> ancestors = ancestorsByNode.get(node);
		if (ancestors == null) {
			ancestors = new ArrayList<IFigure>();
			ancestorsByNode.put(node, ancestors);
		}
		
		if (position < 0 || position > ancestors.size())
			ancestors.add(ancestor);
		else
			ancestors.add(position, ancestor);

		// Add node as a descendant of ancestor
		
		List<IFigure> descendants = descendantsByNode.get(ancestor);
		if (descendants == null) {
			descendants = new ArrayList<IFigure>();
			descendantsByNode.put(ancestor, descendants);
		}
		
		descendants.add(node);
		
		// Add ancestor as a target of node's ancestor connection
		
		OneToManyConnection connection = ancestorConnections.get(node);
		connection.addTargetAnchor(ancestor);
		
		decorateNode(ancestor);
		add(ancestor);
		
		// Create an ancestor connection for ancestor

		connection = createOneToManyConnection();
		connection.setSourceAnchor(ancestor);
		ancestorConnections.put(ancestor, connection);
		add(connection);
	}
	
	public IFigure[] getAncestors(IFigure node) {
		List<IFigure> ancestors = ancestorsByNode.get(node);
		if (ancestors == null)
			return new IFigure[0];
		return ancestors.toArray(new IFigure[0]);
	}
	
	public IFigure[] getDescendants(IFigure node) {
		List<IFigure> descendants = descendantsByNode.get(node);
		if (descendants == null)
			return new IFigure[0];
		return descendants.toArray(new IFigure[0]);
	}

	protected OneToManyConnection createOneToManyConnection() {
		return new OneToManyConnection();
	}
	
	protected void decorateNode(final IFigure node) {
		if (node instanceof ISelectableFigure) {
			node.addPropertyChangeListener(CoupleFigure.SELECTION_PROPERTY, new PropertyChangeListener() {
	
				public void propertyChange(PropertyChangeEvent event) {
					if (Boolean.TRUE.equals(event.getNewValue())) {
						if (selectedNode != null && selectedNode != node)
							selectedNode.setSelected(false);
						selectedNode = (ISelectableFigure) node;
					}
				}
	
			});
		}
	}

	public IFigure getSelectedNode() {
		return selectedNode;
	}

}
